好的 昨天我們初步看完component 相關的架構
今天來真的面對專案裡面的功能 那就是登入與登出的詳細實作
首先 我們是如何決定顯示頁面 這在上一篇有提到 containers/App.jsx 實作
// 判斷登入狀態決定回傳component
if (_IsLogin) {
_ResultPage = <MuiThemeProvider muiTheme={ThemeDefault}>
<div>
<Header styles={styles.header}
handleChangeRequestNavDrawer={this.handleChangeRequestNavDrawer.bind(this)}>
</Header>
<LeftDrawer navDrawerOpen={this.state._IsDrawerOpen}
menus={Data.menus}
username="User Admin">
</LeftDrawer>
<div style={styles.container}>
{this.props.children}
</div>
</div>
</MuiThemeProvider>
} else {
_ResultPage = <HomePage></HomePage>
}
OK 所以沒有登入的狀態下就是載入 HomePage 這一個component
And then HomePage Component 比較重要的地方在於 多國語言如何實做起來
首先 import 事情不能少
import {translate} from 'react-i18next';
放入要翻譯的Key到相對應的Html Tag
<h2>{t('UsableFeatures')}</h2>
最後,整個 component 要把它 export 出去
export default translate()(HomePage);
好 接下來我們來看如何做登入與登出的動作
首先 登入
當然是排一個去 login component 的 link
<Link to="/login" className="external">
{t('login')}
</Link>
然後我們來看 Login Component 在做什麼
先把需要import的部分弄進來
// Initial Library
import React from 'react';
import {
Link
} from 'react-router';
// Materrital UI Library
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import Paper from 'material-ui/Paper';
import RaisedButton from 'material-ui/RaisedButton';
import FlatButton from 'material-ui/FlatButton';
import Checkbox from 'material-ui/Checkbox';
import PersonAdd from 'material-ui/svg-icons/social/person-add';
import Help from 'material-ui/svg-icons/action/help';
import TextField from 'material-ui/TextField';
// 初始樣式設定
import themeDefault from '../../themeConfig';
// 樣式表引入
import styles from '../../styleConfig/LoginPage';
看重點的 components/LoginPage.jsx 如何做登入按鈕的function
<RaisedButton
label="Login"
primary={true}
style={styles.loginBtn}
onClick={this.props.onSubmitLogin(this.props.Email, this.props.Password)} />
再來看一下 containers/LoginPage.jsx 如何連接
// loading Library
import { connect } from 'react-redux';
// loading Component
import LoginPage_CP from '../../components/LoginPage';
// loading Action
import { UserLogin, changeLoginEmail, changeLoginPwd } from '../../redux/actions/InitialActions';
export default connect(
// 從這裡把State的狀態值抽出來,然後component那邊就可以用this.props.Email 把它放在function 當成參數來傳
(state) => ({
Email: state.getIn(['InitReducer', 'Email']),
Password: state.getIn(['InitReducer', 'Password'])
}),
(dispatch) => ({
onChangeUserEmail: event => {
dispatch(changeLoginEmail(event.target.value))
},
onChangeUserPassword: event => (
dispatch(changeLoginPwd(event.target.value))
),
onSubmitLogin: (_email, _password) => () => (
dispatch(UserLogin(_email, _password))
)
}),
)(LoginPage_CP);
重點1 : 把你要連結的LoginPAge_CP Component 連結進來
重點2 : 把對應的Action InitialActions 讀取進來
重點3 : 透過connect 你的(state) 抽出來的東西就是 要把state Tree 裡面的值 取出來給component做使用
重點4 : (dispatch) 就是去承接 你component所發出來的function
而 我這邊的function 包含了 Email值的變動 Password值的變動 還有最後送出去做登入的動作
OK 最後我們來看一下 這三個方法我們怎麼執行
// 更換Email
export const changeLoginEmail = () => ({
type: CHANGE_Email,
payload: {
Email: "rd02@458.com.tw"
}
});
// 更換Password
export const changeLoginPwd = (pwd) => ({
type: CHANGE_Password,
payload: {
Password: pwd
}
});
帳號與密碼的方法 就是發出相對應的dispatch 去通知reducer 對state tree做更新 修改的動作
然後是我們的登入動作
export const UserLogin = (_email, _password) => {
var formData = new FormData();
formData.append("email", _email);
formData.append("password", _password);
return (dispatch) => {
dispatch(showSpinner());
fetch("http://xxx.xxx.xxx/api/login", {
method: "POST",
body: formData
})
.then(function(response) {
return response.json();
})
.then(function(jsonData) {
if (jsonData.IsSuccess) {
dispatch({
type: USER_Login_Success,
payload: {
Token: jsonData.result,
}
});
localStorage.setItem("LoginData", JSON.stringify({
'IsLogin': true
}));
dispatch(hideSpinner());
browserHistory.push('/');
} else {
alert(jsonData.result);
}
})
.catch(function(e) {
console.log(e);
})
}
};
這裡看起來很多 但簡單說 先把你的帳號密碼包起來
然後透過fetch function 送到後端
成功登入之後 我們呼叫localstorage 去對LoginData做異動 這樣後續就可以拿來作為是否登入的判斷依據
OK 就可以把我們的網頁 用 browserHistory.push('/') 就可以看到我們登入後的畫面
最後 我們來看登出的動作
簡單說 你在Action 裡面只要把它 dispatch 出去
因為他的重點就要更新 state tree
export const userLogout = createAction('USER_Logout');
再來 我們看更新的 Reducer 如何寫
// 關注User Email Change
CHANGE_Email: (state, {payload}) => {
console.log("Reducer : ", payload.Email)
return state.merge({Email: payload.Email,})
},
// 關注User Password Change
CHANGE_Password: (state, {payload}) => (
state.merge({Password: payload.Password,})
),
// 登入成功
USER_Login_Success: (state, {payload}) => {
return state.merge({IsLogin: true, Token: payload.Token});
},
// 登出成功
USER_Logout: (state) => {
return state.merge({IsLogin: false, Token: "", Email: "", Password: ""});
}
我想邏輯上應該是很容易理解的
我在寫的時候唯一覺的有不一樣的地方就是
function decoration 的差別
'()' 不需要去做 return
'{}' 就需要去做 return 值才會真的做改變
OK 這就是登入與登出的部分 明天我們就會前進到 相關List Data 的載入